-------------------------------------------------------------------------------
-- Title      : Handshake bus synchronizer for crossing clock domains
-- Project    : 
-------------------------------------------------------------------------------
-- File       : crossDomainSync.vhd
-- Author     : Paul W
-- Company    : 
-- Created    : 2012-12-08
-- Last update: 2012-12-09
-- Platform   : 
-- Standard   : VHDL'93
-------------------------------------------------------------------------------
-- Description: For use in cases with two clock domains, the source domain will
--              sample its bus and indicate the sample is ready. Only when the
--              dest. domain acknowledges the sample will a new value be
--              obtained.
--              
--              We are using a 4 part handshake to transfer data between
--              domains. There is inherently data loss in this operation, but
--              useful for things like comparing ptrs in 2 clock domains.
--              1.) Ack is low, Ready is Low   -> Sample data, Drive ready high
--              2.) Ack is low, Ready is High  -> Dst gets data, drive ack high
--              3.) Ack is High, Ready is High -> Ack received, drive ready low
--              4.) Ack is High, Ready is Low  -> No 'ready', drive ack low
--              
-------------------------------------------------------------------------------
-- Copyright (c) 2012 
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2012-12-08  1.0      paul    Created
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

entity crossDomainSync is
  
  generic (
    WIDTH : integer := 8);

  port (
    in_rst    : in  std_logic;
    in_srcClk : in  std_logic;
    in_data   : in  std_logic_vector(WIDTH-1 downto 0);
    in_ack    : in  std_logic;          -- From dst domain
    out_data  : out std_logic_vector(WIDTH-1 downto 0);
    out_ready : out std_logic);

end entity crossDomainSync;

architecture rtl of crossDomainSync is

  signal dataHoldReg  : std_logic_vector(WIDTH-1 downto 0);
  signal readyHoldReg : std_logic;
  
begin  -- architecture rtl

  -- Sample the data from the src domain. 'Ready' when we've sampled.
  -- Do not sample again until ack has gone low again.
  srcSample_proc : process (in_srcClk, in_rst) is
  begin  -- process srcSample_proc
    if in_rst = '1' then                -- asynchronous reset (active high)
      dataHoldReg  <= (others => '0');
      readyHoldReg <= '0';
    elsif rising_edge(in_srcClk) then   -- rising clock edge
      if readyHoldReg = '0' and in_ack = '0' then
        dataHoldReg  <= in_data;
        readyHoldReg <= '1';
      end if;
      if in_ack = '1' then
        readyHoldReg <= '0';
      end if;
    end if;
  end process srcSample_proc;

  out_ready <= readyHoldReg;
  out_data  <= dataHoldReg;
  
end architecture rtl;
